home *** CD-ROM | disk | FTP | other *** search
- /*
- name: intersct.c
-
- Intersection-routines
- ---------------------
-
- These routines will calculate the t-parameter of a line,
- which corresponds to the point where the given line intersects with
- the given primitive. The routines return zero (0) if no intersection
- occured.
-
- */
-
- #include <stdio.h>
-
- #include "defs.h"
- #include "extern.h"
-
-
- /**********************************************************************
- *
- * Get (possible) intersection with given object
- *
- **********************************************************************/
-
-
- double Intersect_Object(LINE *Line, OBJECT *Object)
- {
- LINE TransformedLine;
- double t;
- long i;
- VECTOR tempv;
-
- CopyPoint(&TransformedLine.Origin,&Line->Origin);
- CopyVector(&TransformedLine.Direction,&Line->Direction);
-
- if(Object->Transform.NumTransforms>0) {
- for(i=Object->Transform.NumTransforms-1L;i>=0L;i--) {
- switch(Object->Transform.Entry[i].Type) {
- case TRANSFORM_SCALE:
- TransformedLine.Origin.x=TransformedLine.Origin.x/Object->Transform.Entry[i].Values.x;
- TransformedLine.Origin.y=TransformedLine.Origin.y/Object->Transform.Entry[i].Values.y;
- TransformedLine.Origin.z=TransformedLine.Origin.z/Object->Transform.Entry[i].Values.z;
- TransformedLine.Direction.x=TransformedLine.Direction.x/Object->Transform.Entry[i].Values.x;
- TransformedLine.Direction.y=TransformedLine.Direction.y/Object->Transform.Entry[i].Values.y;
- TransformedLine.Direction.z=TransformedLine.Direction.z/Object->Transform.Entry[i].Values.z;
- break;
- case TRANSFORM_MOVE:
- TransformedLine.Origin.x=TransformedLine.Origin.x-Object->Transform.Entry[i].Values.x;
- TransformedLine.Origin.y=TransformedLine.Origin.y-Object->Transform.Entry[i].Values.y;
- TransformedLine.Origin.z=TransformedLine.Origin.z-Object->Transform.Entry[i].Values.z;
- break;
- case TRANSFORM_ROTATE:
- NegVector(&tempv,&Object->Transform.Entry[i].Values);
- RotatePoint(&TransformedLine.Origin,&tempv);
- RotateVector(&TransformedLine.Direction,&tempv);
- break;
- case TRANSFORM_NONE:
- default:
- break;
- }
- }
- }
-
- switch(Object->ShapeType) {
- case SHAPE_PLANE:
- t=Intersect_Plane(&TransformedLine, (PLANE *)(Object->Shape));
- break;
- case SHAPE_SPHERE:
- t=Intersect_Sphere(&TransformedLine, (SPHERE *)(Object->Shape));
- break;
- case SHAPE_ELLIPSOID:
- t=Intersect_Ellipsoid(&TransformedLine, (ELLIPSOID *)(Object->Shape));
- break;
- case SHAPE_TRIANGLE:
- t=Intersect_Triangle(&TransformedLine, (TRIANGLE *)(Object->Shape));
- break;
- case SHAPE_BOX:
- t=Intersect_Box(&TransformedLine, (BOX *)(Object->Shape));
- break;
- case SHAPE_DISC:
- t=Intersect_Disc(&TransformedLine, (DISC *)(Object->Shape));
- break;
- case SHAPE_CYLINDER:
- t=Intersect_Cylinder(&TransformedLine, (CYLINDER *)(Object->Shape));
- break;
- default:
- t=0.0;
- }
-
- return(t);
- }
-
-
-
- /**********************************************************************
- *
- * These are the actual intersection calculation routines
- *
- **********************************************************************/
-
-
- double Intersect_Plane(LINE *Line, PLANE *Plane)
- {
- register double t,pnx,pny,pnz,a,tmp;
- double lvx,lvy,lvz,lx0,ly0,lz0;
-
- PlaneIntersectionAttempts++;
-
- lvx=Line->Direction.x; lvy=Line->Direction.y; lvz=Line->Direction.z;
- lx0=Line->Origin.x; ly0=Line->Origin.y; lz0=Line->Origin.z;
- pnx=Plane->Normal.x; pny=Plane->Normal.y; pnz=Plane->Normal.z; a=Plane->a;
-
- tmp=pnx*lvx+pny*lvy+pnz*lvz;
- if(tmp!=0.0) {
- t=-(pnx*lx0+pny*ly0+pnz*lz0-a)/tmp;
- if(t<EPSILON) { t=0.0; }
- else { PlaneIntersections++; }
- }
- else { t=0.0; }
-
- return(t);
- }
-
-
-
- double Intersect_Sphere(LINE *Line, SPHERE *Sphere)
- {
- double vx,vy,vz,lx0,ly0,lz0,sx0,sy0,sz0,r;
-
- register double s,sroot,vxdx,vydy,vzdz,vxsqr,vysqr,vzsqr;
- double t;
- double dx,dy,dz;
- double dxsqr,dysqr,dzsqr;
- double vsum,t1,t2;
-
- SphereIntersectionAttempts++;
-
- vx=Line->Direction.x; vy=Line->Direction.y; vz=Line->Direction.z;
- lx0=Line->Origin.x; ly0=Line->Origin.y; lz0=Line->Origin.z;
- sx0=Sphere->Centre.x; sy0=Sphere->Centre.y; sz0=Sphere->Centre.z;
- r=Sphere->r;
-
- /* These are used more than once, */
- dx=lx0-sx0; dy=ly0-sy0; dz=lz0-sz0; /* thus much time is saved by not */
- vxdx=vx*dx; vydy=vy*dy; vzdz=vz*dz; /* performing the same operation */
- dxsqr=dx*dx; dysqr=dy*dy; dzsqr=dz*dz; /* twice (or even more). */
- vxsqr=vx*vx; vysqr=vy*vy; vzsqr=vz*vz;
-
- vsum=(vxsqr+vysqr+vzsqr);
-
- s=-(vxdx+vydy+vzdz);
-
- sroot=2*(vxdx*(vydy+vzdz)+vydy*vzdz)+r*r*vsum;
- sroot-=vxsqr*(dysqr+dzsqr)+vysqr*(dxsqr+dzsqr)+vzsqr*(dxsqr+dysqr);
-
- if(sroot>=0) {
- sroot=sqrt(sroot);
-
- t1=(s+sroot)/vsum;
- t2=(s-sroot)/vsum;
-
- if((t1>EPSILON)&&((t1<t2)||(t2<EPSILON))) {
- t=t1;
- SphereIntersections++;
- }
- else {
- if((t2>EPSILON)&&((t2<t1)||(t1<EPSILON))) {
- t=t2;
- SphereIntersections++;
- }
- else { t=(double) 0; }
- }
- }
- else t=(double) 0;
-
- return(t);
- }
-
-
-
- double Intersect_Ellipsoid(LINE *Line, ELLIPSOID *Ellipsoid)
- {
- double vx,vy,vz,lx0,ly0,lz0,ex0,ey0,ez0,a,b,c;
-
- register double sroot,asqr,bsqr,csqr,vxdx,vydy,vzdz;
- double t;
- double dx,dy,dz;
- double vxsqr,vysqr,vzsqr,dxsqr,dysqr,dzsqr;
- double r,s,t1,t2;
-
- EllipsoidIntersectionAttempts++;
-
- vx=Line->Direction.x; vy=Line->Direction.y; vz=Line->Direction.z;
- lx0=Line->Origin.x; ly0=Line->Origin.y; lz0=Line->Origin.z;
- ex0=Ellipsoid->Centre.x; ey0=Ellipsoid->Centre.y; ez0=Ellipsoid->Centre.z;
- a=Ellipsoid->Radius.x; b=Ellipsoid->Radius.y; c=Ellipsoid->Radius.z;
-
- asqr=a*a; bsqr=b*b; csqr=c*c; /* These are used more than once, */
- dx=lx0-ex0; dy=ly0-ey0; dz=lz0-ez0; /* thus much time is saved by not */
- vxdx=vx*dx; vydy=vy*dy; vzdz=vz*dz; /* performing the same operation */
- dxsqr=dx*dx; dysqr=dy*dy; dzsqr=dz*dz; /* twice (or even more). */
- vxsqr=vx*vx; vysqr=vy*vy; vzsqr=vz*vz;
-
- s=-((vxdx/asqr)+(vydy/bsqr)+(vzdz/csqr));
-
- sroot=csqr*(vxsqr*bsqr+vysqr*asqr)+vzsqr*asqr*bsqr;
- sroot+=2*(vxdx*(csqr*vydy+bsqr*vzdz)+asqr*vydy*vzdz);
- sroot-=vxsqr*(csqr*dysqr+bsqr*dzsqr);
- sroot-=vysqr*(csqr*dxsqr+asqr*dzsqr);
- sroot-=vzsqr*(bsqr*dxsqr+asqr*dysqr);
-
- if(sroot>=0) {
- sroot=sqrt(sroot)/(a*b*c);
-
- r=((vxsqr/asqr)+(vysqr/bsqr)+(vzsqr/csqr));
-
- t1=(s+sroot)/r;
- t2=(s-sroot)/r;
-
- if((t1>EPSILON)&&((t1<t2)||(t2<EPSILON))) {
- t=t1;
- EllipsoidIntersections++;
- }
- else {
- if((t2>EPSILON)&&((t2<t1)||(t1<EPSILON))) {
- t=t2;
- EllipsoidIntersections++;
- }
- else { t=(double) 0; }
- }
- }
- else t=0.0;
-
- return(t);
- }
-
-
- double Intersect_Triangle(LINE *Line, TRIANGLE *Triangle)
- {
- double t=0.0,ttmp,pnx,pny,pnz,a;
- double lvx,lvy,lvz,lx0,ly0,lz0,angle1,angle2,angle3;
- VECTOR v1,v2,v3;
- POINT ip;
-
- TriangleIntersectionAttempts++;
-
- lvx=Line->Direction.x; lvy=Line->Direction.y; lvz=Line->Direction.z;
- lx0=Line->Origin.x; ly0=Line->Origin.y; lz0=Line->Origin.z;
- pnx=Triangle->Plane.Normal.x; pny=Triangle->Plane.Normal.y; pnz=Triangle->Plane.Normal.z; a=Triangle->Plane.a;
-
- ttmp=-(pnx*lx0+pny*ly0+pnz*lz0-a)/(pnx*lvx+pny*lvy+pnz*lvz);
- if(ttmp>EPSILON) {
- ip.x=Line->Origin.x+ttmp*Line->Direction.x; /* ip = intersection point */
- ip.y=Line->Origin.y+ttmp*Line->Direction.y;
- ip.z=Line->Origin.z+ttmp*Line->Direction.z;
-
- if((ip.x>Triangle->Min.x)&&(ip.x<Triangle->Max.x)&&(ip.y>Triangle->Min.y)&&(ip.y<Triangle->Max.y)&&(ip.z>Triangle->Min.z)&&(ip.z<Triangle->Max.z)) {
- CreateVector(&v1,Triangle->Corners[1].x-Triangle->Corners[0].x,Triangle->Corners[1].y-Triangle->Corners[0].y,Triangle->Corners[1].z-Triangle->Corners[0].z);
- CreateVector(&v2,Triangle->Corners[2].x-Triangle->Corners[0].x,Triangle->Corners[2].y-Triangle->Corners[0].y,Triangle->Corners[2].z-Triangle->Corners[0].z);
- angle1=VectorsAngle(&v1,&v2);
- CreateVector(&v3,ip.x-Triangle->Corners[0].x,ip.y-Triangle->Corners[0].y,ip.z-Triangle->Corners[0].z);
- angle2=VectorsAngle(&v1,&v3);
- angle3=VectorsAngle(&v2,&v3);
- if((angle2+angle3)<=(angle1+EPSILON)) {
- CreateVector(&v1,Triangle->Corners[1].x-Triangle->Corners[2].x,Triangle->Corners[1].y-Triangle->Corners[2].y,Triangle->Corners[1].z-Triangle->Corners[2].z);
- CreateVector(&v2,Triangle->Corners[0].x-Triangle->Corners[2].x,Triangle->Corners[0].y-Triangle->Corners[2].y,Triangle->Corners[0].z-Triangle->Corners[2].z);
- angle1=VectorsAngle(&v1,&v2);
- CreateVector(&v3,ip.x-Triangle->Corners[2].x,ip.y-Triangle->Corners[2].y,ip.z-Triangle->Corners[2].z);
- angle2=VectorsAngle(&v1,&v3);
- angle3=VectorsAngle(&v2,&v3);
- if((angle2+angle3)<=(angle1+EPSILON)) {
- t=ttmp;
- TriangleIntersections++;
- }
- }
- }
- }
-
- return(t);
- }
-
-
- double Intersect_Box(LINE *Line, BOX *Box)
- {
- double t=0.0,told=-1.0,ttmp,pnx,pny,pnz,a;
- double lvx,lvy,lvz,lx0,ly0,lz0;
- int i;
- POINT ip;
-
- BoxIntersectionAttempts++;
-
- lvx=Line->Direction.x; lvy=Line->Direction.y; lvz=Line->Direction.z;
- lx0=Line->Origin.x; ly0=Line->Origin.y; lz0=Line->Origin.z;
- for(i=0;i<6;i++) {
- pnx=Box->Planes[i].Normal.x; pny=Box->Planes[i].Normal.y; pnz=Box->Planes[i].Normal.z; a=Box->Planes[i].a;
-
- ttmp=-(pnx*lx0+pny*ly0+pnz*lz0-a)/(pnx*lvx+pny*lvy+pnz*lvz);
- if((ttmp>EPSILON)&&((told<0.0)||(ttmp<told))) {
- switch(i) {
- case 0:
- case 1:
- ip.y=Line->Origin.y+ttmp*Line->Direction.y;
- ip.z=Line->Origin.z+ttmp*Line->Direction.z;
- if((ip.y>=Box->Corners[0].y)&&(ip.y<=Box->Corners[1].y)&&(ip.z>=Box->Corners[0].z)&&(ip.z<=Box->Corners[1].z)) {
- told=ttmp;
- }
- break;
- case 2:
- case 3:
- ip.x=Line->Origin.x+ttmp*Line->Direction.x;
- ip.z=Line->Origin.z+ttmp*Line->Direction.z;
- if((ip.x>=Box->Corners[0].x)&&(ip.x<=Box->Corners[1].x)&&(ip.z>=Box->Corners[0].z)&&(ip.z<=Box->Corners[1].z)) {
- told=ttmp;
- }
- break;
- case 4:
- case 5:
- ip.x=Line->Origin.x+ttmp*Line->Direction.x;
- ip.y=Line->Origin.y+ttmp*Line->Direction.y;
- if((ip.x>=Box->Corners[0].x)&&(ip.x<=Box->Corners[1].x)&&(ip.y>=Box->Corners[0].y)&&(ip.y<=Box->Corners[1].y)) {
- told=ttmp;
- }
- break;
- }
- }
- }
- if(told>EPSILON) {
- t=told;
- BoxIntersections++;
- }
-
- return(t);
- }
-
-
- double Intersect_Disc(LINE *Line, DISC *Disc)
- {
- register double t,pnx,pny,pnz,a,tmp;
- double lvx,lvy,lvz,lx0,ly0,lz0,dx,dy,dz;
-
- DiscIntersectionAttempts++;
-
- lvx=Line->Direction.x; lvy=Line->Direction.y; lvz=Line->Direction.z;
- lx0=Line->Origin.x; ly0=Line->Origin.y; lz0=Line->Origin.z;
- pnx=Disc->Plane.Normal.x; pny=Disc->Plane.Normal.y; pnz=Disc->Plane.Normal.z; a=Disc->Plane.a;
-
- tmp=pnx*lvx+pny*lvy+pnz*lvz;
- if(tmp!=0.0) {
- t=-(pnx*lx0+pny*ly0+pnz*lz0-a)/tmp;
- if(t<EPSILON) { t=0.0; }
- else {
- dx=(Line->Origin.x+Line->Direction.x*t)-Disc->Centre.x;
- dy=(Line->Origin.y+Line->Direction.y*t)-Disc->Centre.y;
- dz=(Line->Origin.z+Line->Direction.z*t)-Disc->Centre.z;
- if((dx*dx+dy*dy+dz*dz)>(Disc->r*Disc->r)) { t=0.0; }
- else { DiscIntersections++; }
- }
- }
- else { t=0.0; }
-
- return(t);
- }
-
-
- double Intersect_Cylinder(LINE *Line, CYLINDER *Cylinder)
- {
- register double t=0.0,t1,t2,t3,t4,rsqr,lx0lvx,ly0lvy;
- double lvx,lvy,lvz,lx0,ly0,lz0,tmp,tmp2,tmp3;
- POINT ip1,ip2;
-
- CylinderIntersectionAttempts++;
-
- lvx=Line->Direction.x; lvy=Line->Direction.y; lvz=Line->Direction.z;
- lx0=Line->Origin.x; ly0=Line->Origin.y; lz0=Line->Origin.z;
- rsqr=Cylinder->r*Cylinder->r;
-
- lx0lvx=lx0*lvx; ly0lvy=ly0*lvy;
- tmp=2.0*lx0lvx*ly0lvy-lvx*lvx*ly0*ly0-lvy*lvy*lx0*lx0+lvx*lvx*rsqr+lvy*lvy*rsqr;
-
- if(tmp>=0.0) {
- tmp=sqrt(tmp);
- tmp2=-(lx0lvx+ly0lvy);
- tmp3=1.0/(lvx*lvx+lvy*lvy);
- t1=(tmp2+tmp)*tmp3;
- t2=(tmp2-tmp)*tmp3;
- ip1.x=lx0+lvx*t1; ip1.y=ly0+lvy*t1; ip1.z=lz0+lvz*t1;
- ip2.x=lx0+lvx*t2; ip2.y=ly0+lvy*t2; ip2.z=lz0+lvz*t2;
-
- tmp=ip1.x*Cylinder->Discs[0].Plane.Normal.x+ip1.y*Cylinder->Discs[0].Plane.Normal.y+ip1.z*Cylinder->Discs[0].Plane.Normal.z;
- if(tmp>Cylinder->Discs[0].Plane.a) { t1=0.0; }
- else {
- tmp=ip1.x*Cylinder->Discs[1].Plane.Normal.x+ip1.y*Cylinder->Discs[1].Plane.Normal.y+ip1.z*Cylinder->Discs[1].Plane.Normal.z;
- if(tmp>Cylinder->Discs[1].Plane.a) { t1=0.0; }
- }
- tmp=ip2.x*Cylinder->Discs[0].Plane.Normal.x+ip2.y*Cylinder->Discs[0].Plane.Normal.y+ip2.z*Cylinder->Discs[0].Plane.Normal.z;
- if(tmp>Cylinder->Discs[0].Plane.a) { t2=0.0; }
- else {
- tmp=ip2.x*Cylinder->Discs[1].Plane.Normal.x+ip2.y*Cylinder->Discs[1].Plane.Normal.y+ip2.z*Cylinder->Discs[1].Plane.Normal.z;
- if(tmp>Cylinder->Discs[1].Plane.a) { t2=0.0; }
- }
-
- t=0.0;
-
- if((t1<EPSILON)||(t2<EPSILON)) {
- t3=Intersect_Disc(Line, &Cylinder->Discs[0]);
- t4=Intersect_Disc(Line, &Cylinder->Discs[1]);
- if(t1>EPSILON) { t=t1; }
- if((t2>EPSILON)&&((t2<t)||(t<EPSILON))) { t=t2; }
- if((t3>EPSILON)&&((t3<t)||(t<EPSILON))) { t=t3; }
- if((t4>EPSILON)&&((t4<t)||(t<EPSILON))) { t=t4; }
- }
- else {
- if(t1>EPSILON) { t=t1; }
- if((t2>EPSILON)&&((t2<t)||(t<EPSILON))) { t=t2; }
- }
- if(t>EPSILON) { CylinderIntersections++; }
- }
-
- return(t);
- }
-